home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / pctchnqs / 1990 / number3 / stackmon.pas < prev    next >
Pascal/Delphi Source File  |  1990-02-22  |  6KB  |  195 lines

  1. {**********************************************************
  2.   STACKMON.PAS -- By Brian Foley
  3.   Self-activated unit for monitoring stack and heap usage.
  4.   Works with Turbo Pascal 4.0, 5.0, and 5.5.
  5. ***********************************************************}
  6.  
  7. {$S-,R-,I-,B-,D-}
  8.  
  9. unit StackMon;
  10.   {-Unit for monitoring stack and heap usage}
  11.  
  12. interface
  13.  
  14. uses
  15.   Dos;
  16.  
  17. const
  18.   {If ReportStackUsage is True, results are reported automatically
  19.    at the end of the program. Set it to False if you want to display
  20.    results in another manner.}
  21.   ReportStackUsage : Boolean = True;
  22.  
  23. var
  24.   {The following variables, like the two procedures that follow, are
  25.    interfaced solely for the purpose of displaying results. You
  26.    should never alter any of these variables.}
  27.   OurSS : Word;         {value of SS register when program began}
  28.   InitialSP : Word;     {value of SP register when program began}
  29.   LowestSP : Word;      {lowest value for SP register}
  30.   HeapHigh : Pointer;   {highest address pointed to by HeapPtr}
  31.  
  32. procedure CalcStackUsage(var StackUsage : Word;
  33.                          var HeapUsage : LongInt);
  34.   {-Calculate stack and heap usage}
  35.  
  36. procedure ShowStackUsage;
  37.   {-Display stack and heap usage information}
  38.  
  39. {The next two routines are interfaced in case you need or want to
  40.  deinstall the INT $8 handler temporarily, as you might when using
  41.  the Exec procedure in the DOS unit.}
  42.  
  43. procedure InstallInt8;
  44.   {-Save INT $8 vector and install our ISR}
  45.  
  46. procedure RestoreInt8;
  47.   {-Restore the old INT $8 handler if our ISR is installed}
  48.  
  49.   {==========================================================================}
  50.  
  51. implementation
  52.  
  53. type
  54.   SegOfs =                   {structure of a 32-bit pointer}
  55.     record
  56.       Ofst, Segm : Word;
  57.     end;
  58. var
  59.   SaveInt8 : Pointer;        {original INT $8 vector}
  60.   SaveExitProc : Pointer;    {saved value for ExitProc}
  61. const
  62.   {True if our INT $8 handler is installed}
  63.   Int8Installed : Boolean = False;
  64.  
  65.   procedure JumpToOldIsr(OldIsr : Pointer);
  66.     {-Jump to previous ISR from an interrupt procedure}
  67.     inline(
  68.       $5B/         {pop bx          ;bx = Ofs(OldIsr)}
  69.       $58/         {pop ax          ;ax = Seg(OldIsr)}
  70.       $87/$5E/$0E/ {xchg bx,[bp+14] ;Switch old bx and Ofs(OldIsr^)}
  71.       $87/$46/$10/ {xchg ax,[bp+16] ;Switch old ax and Seg(OldIsr^)}
  72.       $89/$EC/     {mov sp,bp       ;Restore registers}
  73.       $5D/         {pop bp          ;at [bp+0]}
  74.       $07/         {pop es          ;at [bp+2]}
  75.       $1F/         {pop ds          ;at [bp+4]}
  76.       $5F/         {pop di          ;at [bp+6]}
  77.       $5E/         {pop si          ;at [bp+8]}
  78.       $5A/         {pop dx          ;at [bp+10]}
  79.       $59/         {pop cx          ;at [bp+12]}
  80.                    {bx and ax already restored; their slots on the}
  81.                    {stack now have OldIsr, where return will go}
  82.       $CB);        {retf            ;chain to OldIsr}
  83.  
  84.   procedure Int8(Flags, CS, IP, AX, BX, CX : Word;
  85.                  DX, SI, DI, DS, ES, BP : Word); interrupt;
  86.     {-Interrupt service routine used to monitor stack/heap usage}
  87.   begin
  88.     {make sure we're in the right stack segment}
  89.     if SSeg = OurSS then
  90.       {Flags "parameter" is where SS:SP was when interrupt occurred}
  91.       if Ofs(Flags) < LowestSP then
  92.         LowestSP := Ofs(Flags);
  93.  
  94.     {compare HeapPtr and HeapHigh, assuming that both pointers
  95.      are normalized}
  96.     if SegOfs(HeapPtr).Segm > SegOfs(HeapHigh).Segm then
  97.       {the segment is higher, so HeapPtr points higher}
  98.       HeapHigh := HeapPtr
  99.     else if SegOfs(HeapPtr).Segm = SegOfs(HeapHigh).Segm then
  100.       {the segment is the same...}
  101.       if SegOfs(HeapPtr).Ofst > SegOfs(HeapHigh).Ofst then
  102.         {and the offset is higher, so HeapPtr points higher}
  103.         HeapHigh := HeapPtr;
  104.  
  105.     {chain to old INT $8 handler}
  106.     JumpToOldISR(SaveInt8);
  107.   end;
  108.  
  109.   procedure InstallInt8;
  110.     {-Save INT $8 vector and install our ISR}
  111.   begin
  112.     {make sure we're not already installed, in case we are called
  113.      twice. if we don't do this check, SaveInt8 could get pointed to
  114.      *our* ISR}
  115.     if not Int8Installed then begin
  116.       GetIntVec($8, SaveInt8);
  117.       SetIntVec($8, @Int8);
  118.       Int8Installed := True;
  119.     end;
  120.   end;
  121.  
  122.   procedure RestoreInt8;
  123.     {-Restore the old INT $8 handler if our ISR is installed}
  124.   begin
  125.     {if we're currently installed, then deinstall}
  126.     if Int8Installed then begin
  127.       SetIntVec($8, SaveInt8);
  128.       Int8Installed := False;
  129.     end;
  130.   end;
  131.  
  132.   procedure CalcStackUsage(var StackUsage : Word;
  133.                            var HeapUsage : LongInt);
  134.     {-Calculate stack and heap usage}
  135.   begin
  136.     {calculate stack usage}
  137.     StackUsage := InitialSP-LowestSP;
  138.  
  139.     {total heap usage = (difference in segments * 16) + difference
  140.      in offsets}
  141.     HeapUsage :=
  142.       (LongInt(SegOfs(HeapHigh).Segm-SegOfs(HeapOrg).Segm) * 16) +
  143.        LongInt(SegOfs(HeapHigh).Ofst-SegOfs(HeapOrg).Ofst);
  144.   end;
  145.  
  146.   procedure ShowStackUsage;
  147.     {-Display stack and heap usage information}
  148.   var
  149.     StackUsage : Word;
  150.     HeapUsage : LongInt;
  151.   begin
  152.     {calculate stack and heap usage}
  153.     CalcStackUsage(StackUsage, HeapUsage);
  154.  
  155.     {show them}
  156.     WriteLn('Stack usage: ', StackUsage, ' bytes.');
  157.     WriteLn('Heap usage:  ', HeapUsage, ' bytes.');
  158.   end;
  159.  
  160.   {$F+}  {Exit handlers are always called FAR!}
  161.   procedure OurExitProc;
  162.     {-Deinstalls our INT $8 handler and reports stack/heap usage}
  163.   begin
  164.     {restore ExitProc}
  165.     ExitProc := SaveExitProc;
  166.  
  167.     {restore INT $8}
  168.     RestoreInt8;
  169.  
  170.     {show results if desired}
  171.     if ReportStackUsage then
  172.       ShowStackUsage;
  173.   end;
  174.   {$F-}
  175.  
  176. begin
  177.   {save current value for SS}
  178.   OurSS := SSeg;
  179.  
  180.   {save current value of SP and account for the return address on
  181.    the stack}
  182.   InitialSP := SPtr+SizeOf(Pointer);
  183.   LowestSP := InitialSP;
  184.  
  185.   {save current position of HeapPtr}
  186.   HeapHigh := HeapPtr;
  187.  
  188.   {install our ISR}
  189.   InstallInt8;
  190.  
  191.   {save ExitProc and install our exit handler}
  192.   SaveExitProc := ExitProc;
  193.   ExitProc := @OurExitProc;
  194. end.
  195.